#if UNITY_EDITOR
using Net.Helper;
using Net.Unity;
using Net.UnityComponent;
using System;
using System.Linq;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

[CustomEditor(typeof(PrefabCollectionComponent), editorForChildClasses: true)]
[CanEditMultipleObjects]
public class PrefabCollectionComponentEditor : Editor
{
    private PrefabCollectionComponent prefabCollection;
    private SerializedProperty prefabInfos;
    private ReorderableList list;

    private void OnEnable()
    {
        prefabCollection = target as PrefabCollectionComponent;
        prefabInfos = serializedObject.FindProperty("prefabInfos");
        list = new ReorderableList(serializedObject, prefabInfos)
        {
            elementHeight = EditorGUIUtility.singleLineHeight * 2f,
            drawHeaderCallback = OnDrawHeader,
            onAddCallback = AddNewElement,
            onRemoveCallback = RemoveElement,
            drawElementCallback = OnDrawElement,
        };
        serializedObject.Update();
        for (int i = 0; i < prefabInfos.arraySize; i++)
        {
            var newElement = prefabInfos.GetArrayElementAtIndex(i);
            var prefab = newElement.FindPropertyRelative("prefab").objectReferenceValue;
            if (prefab != null)
                newElement.FindPropertyRelative("prefabHash").intValue = AssetDatabase.GetAssetPath(prefab).CRC32();
        }
        serializedObject.ApplyModifiedProperties();
    }

    private void OnDrawHeader(Rect rect)
    {
        EditorGUI.LabelField(rect, "注册网络预制体列表");
        prefabInfos.arraySize = EditorGUI.DelayedIntField(new Rect(rect.x + (rect.width - 50f), rect.y, 50, rect.height), prefabInfos.arraySize);
        HandleDragAndDrop(rect);
    }

    private void OnDrawElement(Rect rect, int index, bool isActive, bool isFocused)
    {
        var element = prefabInfos.GetArrayElementAtIndex(index);
        var prefabProp = element.FindPropertyRelative("prefab");
        var prefabHash = element.FindPropertyRelative("prefabHash");
        EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), prefabProp, new GUIContent("prefab"));
        rect.y += EditorGUIUtility.singleLineHeight + 2f;
        if (prefabProp.objectReferenceValue != null && prefabHash.intValue == 0)
            prefabHash.intValue = AssetDatabase.GetAssetPath(prefabProp.objectReferenceValue).CRC32();
        EditorGUI.LabelField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), "prefabHash", prefabHash.intValue.ToString());
    }

    private void AddNewElement(ReorderableList list)
    {
        prefabInfos.InsertArrayElementAtIndex(prefabInfos.arraySize);
    }

    private void RemoveElement(ReorderableList list)
    {
        prefabInfos.DeleteArrayElementAtIndex(list.index);
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        list.DoLayoutList();
        serializedObject.ApplyModifiedProperties();
        if (GUILayout.Button("收集网络预制体"))
        {
            prefabCollection.prefabInfos.Clear();
            var guids = AssetDatabase.FindAssets("t:Prefab");
            foreach (string guid in guids)
            {
                var path = AssetDatabase.GUIDToAssetPath(guid);
                var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                var components = prefab.GetComponents<MonoBehaviour>();
                foreach (var component in components)
                {
                    if (component == null)
                        continue;
                    var typeName = component.GetType().ToString();
                    if (typeName == "Net.UnityComponent.NetworkObject" || typeName == "ActorSystem.ActorView")
                    {
                        prefabCollection.prefabInfos.Add(new PrefabInfo2()
                        {
                            prefab = prefab,
                            prefabHash = path.CRC32(),
                        });
                        break;
                    }
                }
            }
            EditorUtility.SetDirty(prefabCollection);
        }
    }

    private void HandleDragAndDrop(Rect dropArea)
    {
        if (!dropArea.Contains(Event.current.mousePosition))
            return;
        switch (Event.current.type)
        {
            case EventType.DragUpdated:
                DragAndDrop.visualMode = DragAndDrop.objectReferences.All(x => x is GameObject) ? DragAndDropVisualMode.Copy : DragAndDropVisualMode.Rejected;
                Event.current.Use();
                break;

            case EventType.DragPerform:
                foreach (var obj in DragAndDrop.objectReferences)
                {
                    if (obj is GameObject prefab)
                    {
                        AddPrefabToDatabase(prefab);
                    }
                }
                DragAndDrop.AcceptDrag();
                Event.current.Use();
                break;
        }
    }

    private void AddPrefabToDatabase(GameObject prefab)
    {
        for (int i = 0; i < prefabInfos.arraySize; i++)
        {
            var existing = prefabInfos.GetArrayElementAtIndex(i).FindPropertyRelative("prefab").objectReferenceValue;
            if (existing == prefab) return;
        }
        int newIndex = prefabInfos.arraySize;
        prefabInfos.InsertArrayElementAtIndex(newIndex);

        var newElement = prefabInfos.GetArrayElementAtIndex(newIndex);
        newElement.FindPropertyRelative("prefab").objectReferenceValue = prefab;
        newElement.FindPropertyRelative("prefabHash").intValue = AssetDatabase.GetAssetPath(prefab).CRC32();
    }
}
#endif